﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using myFinance.BLL;
using myFinance.Models;
using myFinance.Models.Admin;
using myFinance.Services.Admin;
using System.Security.Principal;
using System.Net;
using Newtonsoft.Json.Linq;
using System.Web.Helpers;
using System.Web.UI.WebControls;

namespace myFinance.Controllers
{
    [HandleError]
    public class CadastroController : Controller
    {
        // This constructor is used by the MVC framework to instantiate the controller using
        // the default forms authentication and membership providers.
        public CadastroController()
            : this(null, null, null)
        {
        }

        // This constructor is not used by the MVC framework but is instead provided for ease
		// of unit testing this type. See the comments at the end of this file for more
		// information.
        public CadastroController(IFormsAuthentication formsAuth, IMembershipService membershipService, IRoleService roleService)
		{
			FormsAuth = formsAuth ?? new FormsAuthenticationService();
            MembershipService = membershipService ?? new MembershipService();
		    RoleService = roleService ?? new RoleService();
		}

        public IFormsAuthentication FormsAuth { get; private set; }

        public IMembershipService MembershipService { get; private set; }

        public IRoleService RoleService { get; private set; }

        [HttpGet]
        public ActionResult FacebookLogin(string token)
        {
            WebClient client = new WebClient();
            string JsonResult = client.DownloadString(string.Concat(
                   "https://graph.facebook.com/me?access_token=", token));
            // Json.Net is really helpful if you have to deal
            // with Json from .Net http://json.codeplex.com/
            JObject jsonUserInfo = JObject.Parse(JsonResult);
            // you can get more user's info here. Please refer to:
            // http://developers.facebook.com/docs/reference/api/user/
            string username = jsonUserInfo.Value<string>("username");
            string name = jsonUserInfo.Value<string>("name");
            string email = jsonUserInfo.Value<string>("email");
            //string locale = jsonUserInfo.Value<string>("locale");
            string gender = jsonUserInfo.Value<string>("gender");
            string birthday = jsonUserInfo.Value<string>("birthday_date");
            int facebook_userID = jsonUserInfo.Value<int>("id");
            
            // verifica se já existe cadastro com esse facebook_userID
            if (PessoaBll.GetPessoaByFacebook_userID(facebook_userID) != null)
            {
                // se já existir, autentica usando o nome de usuário de acordo com o facebook_userID
                FormsAuthentication.SetAuthCookie(PessoaBll.GetPessoaByFacebook_userID(facebook_userID).Usuario, false);
                return RedirectToAction("Index", "Home");                
            }
            else
            {
                // se não existir, redireciona para a tela de cadastro com as informações pré-carregadas
                var user = new RegisterModel();

                user.UserName = PessoaBll.ExisteUsuario(username) ? username + "123" : username;
                user.Nome = name + birthday;
                user.Sexo = gender == "female";
                user.DataNascimento = Convert.ToDateTime(birthday);
                user.Email = email;
                Session["facebook_userID"] = facebook_userID;
                Session["user"] = user;
                Session["facebook_Username"] = username;

                return RedirectToAction("Registro");
            }
        }

        #region LogIn / Entrar (Antigo)
        public ActionResult Entrar()
        {            
            return View();
        }

        [HttpPost]
        public ActionResult Entrar(LogOnModel model, string returnUrl)
        {         
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "O Usuário ou a Senha digitado está incorreto.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }
        #endregion

        #region LogOff / Sair
        public ActionResult Sair()
        {
            FormsAuthentication.SignOut();

            return RedirectToAction("Index", "Home");
        }
        #endregion

        #region Registro
        public ActionResult Registro()
        {
            if (Session["user"] != null)
            {
                return View((RegisterModel)Session["user"]);
            }
            
            return View();
        }

        [HttpPost]
        public ActionResult Registro(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                if (model.UserName.Equals("mestre") || model.UserName.Equals("andre"))
                {
                    // Attempt to register the user
                    MembershipCreateStatus createStatus;
                    Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);

                    if (createStatus == MembershipCreateStatus.Success)
                    {
                        Roles.AddUserToRole(model.UserName, "Administrador");
                        var pessoa = new Pessoa();
                        pessoa.Nome = model.Nome;
                        pessoa.DataCadastro = DateTime.Now;
                        pessoa.DataNascimento = model.DataNascimento;
                        pessoa.Email = model.Email;
                        pessoa.Sexo = model.Sexo;
                        pessoa.Usuario = model.UserName;
                        PessoaBll.Add(pessoa);

                        FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
                        return RedirectToAction("Index", "Home");
                    }
                    else
                    {
                        ModelState.AddModelError("", ErrorCodeToString(createStatus));
                    }
                }
                else
                {
                    // Attempt to register the user
                    MembershipCreateStatus createStatus;
                    Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);

                    if (createStatus == MembershipCreateStatus.Success)
                    {
                        Session["user"] = null;

                        Roles.AddUserToRole(model.UserName, "Usuario");
                        var pessoa = new Pessoa();
                        pessoa.Nome = model.Nome;
                        pessoa.DataCadastro = DateTime.Now;
                        pessoa.DataNascimento = model.DataNascimento;
                        pessoa.Email = model.Email;
                        pessoa.Sexo = model.Sexo;
                        pessoa.Usuario = model.UserName;

                        if (Session["facebook_userID"] != null)
                        {
                            pessoa.facebook_userID = (int)Session["facebook_userID"];
                            // insere a imagem do profile
                            WebRequest req = WebRequest.Create("http://graph.facebook.com/" + Session["facebook_Username"].ToString() + "/picture?type=large");
                            WebResponse response = req.GetResponse();
                            WebImage stream = new WebImage(response.GetResponseStream());
                            stream.Resize(200, 200);
                            pessoa.Avatar = stream.GetBytes();
                        }
                        
                        PessoaBll.Add(pessoa);

                        Session["facebook_userID"] = null;
                        Session["facebook_Username"] = null;

                        FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
                        return RedirectToAction("Index", "Home");
                    }
                    else
                    {
                        ModelState.AddModelError("", ErrorCodeToString(createStatus));
                    }
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }
        #endregion

        #region Mudar a Senha
        [Authorize]
        public ActionResult MudarSenha()
        {
            return View();
        }
        
        [Authorize]
        [HttpPost]
        public ActionResult MudarSenha(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {

                // ChangePassword will throw an exception rather
                // than return false in certain failure scenarios.
                bool changePasswordSucceeded;
                try
                {
                    MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
                    changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
                }
                catch (Exception)
                {
                    changePasswordSucceeded = false;
                }

                if (changePasswordSucceeded)
                {
                    return RedirectToAction("MudarSenhaSucesso");
                }
                else
                {
                    ModelState.AddModelError("", "A senha atual é incorreta ou a senha é inválida.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        public ActionResult MudarSenhaSucesso()
        {
            return View();
        }
        #endregion

        #region Parte de Administração de Usuários
        [Authorize(Roles = "Administrador")]
        public ActionResult Admin()
        {
            ViewBag.Nome = Session["nomeUsuario"];
            AdminViewModel viewModel = new AdminViewModel
            {
                Users = MembershipService.GetAllUsers(),
                Roles = RoleService.GetAllRoles()
            };
			ViewBag.Hash = "#AdministracaoUsuarios";
            return View(viewModel);
        }

        [Authorize(Roles = "Administrador")]
        public ActionResult DeleteRole(string role)
        {
            if (RoleService.RoleExists(role))
            {
                // Cannot delete the Admin role
                //
                if (role == "Administrador")
                {
                    TempData["RoleError"] = "Impossível excluir a regra \"Administrador\".";
                }
                else
                {
                    // Remove the role from all users
                    //
                    try
                    {
                        string[] userNames = RoleService.GetUsersInRole(role);
                        if (userNames != null && userNames.Length > 0)
                        {
                            RoleService.RemoveUsersFromRole(userNames, role);
                        }

                        // Delete the role
                        //
                        try
                        {
                            if (!RoleService.DeleteRole(role, true))
                            {
                                TempData["RoleError"] = "Impossível excluir esta regra.";
                            }
                        }
                        catch (Exception)
                        {
                            TempData["RoleError"] = "Impossível excluir esta regra.";
                        }
                    }
                    catch (Exception)
                    {
                        TempData["RoleError"] = "Impossível excluir usuários desta regra.";
                    }
                }
            }

            return RedirectToAction("Admin");
        }

        [Authorize(Roles = "Administrador")]
        public ActionResult AddRole(string newRole)
        {
            if (RoleService.RoleExists(newRole))
            {
                TempData["RoleError"] = "Esta regra já existe.";
            }
            else
            {
                RoleService.CreateRole(newRole);
            }
            return RedirectToAction("Admin");
        }

        [Authorize(Roles = "Administrador")]
        public ActionResult ToggleRole(string role, string userName)
        {
            try
            {
                MembershipUser user = MembershipService.GetUser(userName, false);
                if (user != null)
                {
                    if (RoleService.RoleExists(role))
                    {
                        if (role == "Administrador" && userName == HttpContext.User.Identity.Name)
                        {
                            TempData["UserError"] = "Não é possível remover o seu próprio usuário da regra \"Administrador\".";
                        }
                        else
                        {
                            if (RoleService.IsUserInRole(userName, role))
                            {
                                try
                                {
                                    RoleService.RemoveUserFromRole(userName, role);
                                }
                                catch (Exception)
                                {
                                    TempData["UserError"] = "Falha ao remover o usuário desta regra.";
                                }
                            }
                            else
                            {
                                try
                                {
                                    RoleService.AddUserToRole(userName, role);
                                }
                                catch (Exception)
                                {
                                    TempData["UserError"] = "Falha ao inserir o usuário nesta regra.";
                                }
                            }
                        }
                    }
                    else
                    {
                        TempData["UserError"] = "Regra não existente.";
                    }
                }
            }
            catch (Exception)
            {
                TempData["UserError"] = "Não foi possível encontrar o usuário.";
            }
            return RedirectToAction("Admin");
        }

        [Authorize(Roles = "Administrador")]
        public ActionResult UnlockUser(string userName)
        {
            try
            {
                MembershipUser user = MembershipService.GetUser(userName, false);

                if (!user.UnlockUser())
                {
                    TempData["UserError"] = "Falha ao desbloquear o usuário.";
                }
            }
            catch (Exception)
            {
                TempData["UserError"] = "Não foi possível encontrar o usuário.";
            }

            return RedirectToAction("Admin");
        }

        [Authorize(Roles = "Administrador")]
        public ActionResult ToggleApproved(string userName)
        {
            if (userName == User.Identity.Name)
            {
                TempData["UserError"] = "Você não pode desativar a si mesmo.";
            }
            else
            {
                try
                {
                    MembershipUser user = MembershipService.GetUser(userName, false);
                    user.IsApproved = !user.IsApproved;
                    try
                    {
                        MembershipService.UpdateUser(user);
                    }
                    catch (Exception)
                    {
                        TempData["UserError"] = "Falha ao atualizar o usuário.";
                    }
                }
                catch (Exception)
                {
                    TempData["UserError"] = "Não foi possível encontrar o usuário.";
                }
            }

            return RedirectToAction("Admin");
        }

        [Authorize(Roles = "Administrador")]
        public ActionResult ResetPassword(string userName)
        {
            try
            {
                string password;
                if (!MembershipService.ResetPassword(userName, User.Identity.Name, out password))
                {
                    TempData["UserError"] = "Não foi possível enviar o email ao usuário. A senha deste usuário é: " + password;
                }
            }
            catch (Exception)
            {
                TempData["UserError"] = "Não foi possível encontrar o usuário.";
            }

            return RedirectToAction("Admin");
        }

        [Authorize(Roles = "Administrador")]
        public ActionResult DeleteUser(string userName)
        {
            if (userName == User.Identity.Name)
            {
                TempData["UserError"] = "Você não pode excluir o seu próprio nome de usuário.";
            }
            else
            {
                if (!MembershipService.DeleteUser(userName, true))
                {
                    TempData["UserError"] = "Não foi possível excluir o usuário.";
                }
            }

            return RedirectToAction("Admin");
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User.Identity is WindowsIdentity)
            {
                throw new InvalidOperationException("Windows authentication is not supported.");
            }

            // Register activity for the user.
            Membership.GetUser(User.Identity.Name, true);
        }
        #endregion

        #region Status Codes
        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "Este nome de usuário já existe. Por favor digite um nome de usário diferente.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "Um nome de usuário com este endereço de e-mail já existe. Por favor digite um endereço de e-mail diferente.";

                case MembershipCreateStatus.InvalidPassword:
                    return "A senha informada é inválida. Por favor, digite uma senha válida.";

                case MembershipCreateStatus.InvalidEmail:
                    return "O endereço de e-mail informado é inválido. Por favor verifique e tente novamente.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "A resposta à pergunta de recuperação de senha é inválida. Por favor verifique e tente novamente.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "A pergunta de recuperação de senha é inválida. Por favor verifique e tente novamente.";

                case MembershipCreateStatus.InvalidUserName:
                    return "O nome de usuário digitado é inválido. Por favor verifique e tente novamente.";

                case MembershipCreateStatus.ProviderError:
                    return "O provedor de autenticação retornou um erro. Por favor verifique e tente novamente. Se o problema persistir, por favor entre em contato com o administrador do sistema.";

                case MembershipCreateStatus.UserRejected:
                    return "A solicitação de criação de usuário foi cancelada. Por favor verifique e tente novamente. Se o problema persistir, por favor entre em contato com o administrador do sistema.";

                default:
                    return "Ocorreu um erro desconhecido. Por favor verifique e tente novamente. Se o problema persistir, por favor entre em contato com o administrador do sistema.";
            }
        }
        #endregion
    }
}
